package com.ss.android.newmedia.h;

import static com.bytedance.common.plugin.framework.update.PluginUpdateHelper.UpdatePluginExtras;

import android.content.Context;
import android.os.Process;
import android.text.TextUtils;

import com.bytedance.common.plugin.framework.PluginManager;
import com.bytedance.common.plugin.framework.model.InstallPluginItem;
import com.bytedance.common.plugin.framework.model.Plugin;
import com.bytedance.common.plugin.framework.model.ProcessType;
import com.bytedance.common.plugin.framework.update.PluginUpdateHelper;
import com.bytedance.common.plugin.framework.util.PluginUtil;
import com.bytedance.common.plugin.interfaces.pushmanager.classhandle.PushClassLoader;
import com.bytedance.common.plugin.interfaces.pushmanager.classhandle.PushClassTest;
import com.bytedance.common.utility.Logger;
import com.ss.android.common.AppContext;
import com.ss.android.common.lib.MobClickCombiner;
import com.ss.android.common.util.ToolUtils;

import java.io.File;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import inline.PluginExtractor;

public final class PluginInstaller {
    private static volatile boolean isInstallInvoked = false;
    private static volatile boolean sPluginInstallFinishListenerInvoked = false;
    private static OnPluginInstallFinishListener sOnPluginInstallFinishListener = null;

    public static void setOnPluginInstallFinishListener(OnPluginInstallFinishListener onPluginInstallFinishListener) {
        PluginInstaller.sOnPluginInstallFinishListener = onPluginInstallFinishListener;
    }

    public static void tryInstall(AppContext appContext, boolean force, boolean[] inCurrentThread) throws Throwable {
        if (!force) {
            if ((PluginInstaller.isInstallInvoked || appContext == null) ) {
                if (PluginInstaller.isInstallInvoked) {
                    PluginInstaller.notifyPluginInstallFinish();
                } else {
                    return;
                }
            }
        }
        if (Logger.debug()) {
            Logger.d("Plugin", "force = " + force);
        }

        PluginInstaller.isInstallInvoked = true;
        if (inCurrentThread[0]) {
            PluginInstaller.tryInstall(appContext);
            return;
        }
        new DexInstaller("DexInstaller", appContext).start();
    }

    public static void onEvent(Context context, String event, long costTime, String pluginPackageName) {
        if (context != null && !android.support.design.a.isTextEmpty(pluginPackageName)) {
            try {
                InstallPluginItem pluginItem = com.bytedance.common.plugin.framework.update.PluginUpdateHelper.a(pluginPackageName);
                if (pluginItem != null) {
                    MobClickCombiner.onEvent(context, "PluginInstaller", event, costTime, 0, pluginItem.toJO());
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }

    public static boolean isCronetPluginInstalled() {
        return PluginManager.getPlugin("com.bytedance.common.plugin.cronet") != null;
    }

    public static void reportInstallResult(Context context, String pluginPackageName) {
        if (context != null && !android.support.design.a.isTextEmpty(pluginPackageName)) {
            try {
                if (PluginInstaller.isCommonPluginLiteInstalled()) {
                    PluginInstaller.onEvent(context, pluginPackageName + ".install_success", 0, pluginPackageName);
                    return;
                } else {
                    PluginInstaller.onEvent(context, pluginPackageName + ".install_fail", 0, pluginPackageName);
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }

    public static void installPlugins(AppContext appContext, ProcessType processType, OnPluginInstallFinishListener pluginInstallFinishListener) {
        try {
            long installStartTs = System.currentTimeMillis();
            PluginManager.ensurePluginManagerInstance(appContext.getContext());
            PluginUpdateHelper.create(appContext.getContext(),
                    appContext.getUpdateVersionCode(),
                    appContext.getManifestVersion(),
                    processType,
                    new UpdatePluginExtras(pluginInstallFinishListener, appContext, processType, installStartTs));
            com.ss.android.l.c.c();
            String curProcessName = ToolUtils.getCurProcessName(appContext.getContext());
            if (ToolUtils.isMainProcess(appContext.getContext()) && !PluginInstaller.isCommonPluginLiteInstalled()) {
                PushClassLoader.hackClassLoader(appContext.getContext());
            }

            Logger.d("Plugin", "installPlugins: processName = " + curProcessName);
            if (curProcessName == null) {
                return;
            }
            if (!curProcessName.endsWith(":push")) {
                if (!curProcessName.endsWith(":pushservice")) {
                    return;
                }

                try {
                    PushClassTest.testPushServiceClass();
                } catch (Throwable throwable) {
                    try {
                        Logger.d("Plugin", "installPlugins: kill " + curProcessName);
                        Process.killProcess(Process.myPid());
                    } catch (Exception exception) {
                        Logger.e("Plugin", "PluginUpdateHelper.init failed.", ((Throwable) exception));
                    }
                }
                return;
            }

            try {
                PushClassTest.testPushClass();
            } catch (Throwable throwable) {
                try {
                    Logger.d("Plugin", "installPlugins: kill " + curProcessName);
                    Process.killProcess(Process.myPid());
                } catch (Exception e) {
                    Logger.e("Plugin", "PluginUpdateHelper.init failed.", e);
                }
            }
        } catch (Exception e) {
            Logger.e("Plugin", "PluginUpdateHelper.init failed.", e);
        }
    }

    static void tryInstall(AppContext appContext) throws Throwable {
        if (Logger.debug()) {
            Logger.d("Plugin", "tryInstall start");
        }
        PluginManager.ensurePluginManagerInstance(appContext.getContext());
        PluginManager pluginManager = PluginManager.getPluginManager();
        if (pluginManager != null) {
            Set<InstallPluginItem> installPluginItems = com.ss.android.newmedia.h.a.installPluginItems;
            if (Logger.debug()) {
                Logger.d("Plugin", "installPluginItems = " + installPluginItems);
            }

            LinkedHashSet<String> pluginPackageNameSet = new LinkedHashSet();
            Iterator<InstallPluginItem> iterator = installPluginItems.iterator();
            while (iterator.hasNext()) {
                InstallPluginItem installPluginItem = iterator.next();
                if (PluginManager.checkPlugin(installPluginItem).booleanValue()) {
                    continue;
                }

                if (Logger.debug()) {
                    Logger.d("Plugin", installPluginItem.packageName);
                }

                pluginPackageNameSet.add(installPluginItem.packageName);
                Plugin.mPluginInfoMap.put(installPluginItem.packageName,
                        new Plugin.PluginInfo(
                                installPluginItem.proxyClass,
                                installPluginItem.pluginClass,
                                installPluginItem.resourceType,
                                installPluginItem.processType,
                                installPluginItem.processNameSuffix,
                                installPluginItem.processNameSuffixList,
                                Boolean.TRUE));
                String pluginPackageName = installPluginItem.packageName;
                String pluginApkUri = installPluginItem.apkUri;
                int versionCode = installPluginItem.apkVersionCode.intValue();
                String pluginApkMD5 = installPluginItem.apkMD5;
                if (TextUtils.isEmpty(pluginPackageName)) {
                    continue;
                }

                if (PluginManager.sContext == null) {
                    continue;
                }

                if (TextUtils.isEmpty(pluginApkUri)) {
                    continue;
                }

                if (!Plugin.isTargetProcess(PluginManager.sContext, pluginPackageName)) {
                    continue;
                }

                if (Logger.debug()) {
                    Logger.d("Plugin", "PluginManager install start packageName = " + pluginPackageName);
                }

                Plugin plugin = PluginManager.sPluginMap.get(pluginPackageName);
                if (plugin != null && plugin.isPluginInstalled(new Object[]{Integer.valueOf(versionCode), pluginApkMD5})) {
                    if (!Logger.debug()) {
                        continue;
                    }
                    Logger.d("Plugin", "PluginManager isPluginInstalled = true");
                    continue;
                }

                if (plugin != null) {
                    PluginManager.sPluginMap.remove(pluginPackageName);
                    PluginManager.deletePluginFile(pluginPackageName);
                }

                String dstPath = Plugin.tryCopyPluginApk(PluginManager.sContext,
                        pluginApkUri,
                        PluginManager.pluginDir() + "/" + pluginPackageName + "/apk/" + pluginPackageName + ".apk");
                Plugin newPlugin = PluginManager.createPlugin(pluginPackageName, dstPath);
                if (newPlugin == null) {
                    continue;
                }
                if (Logger.debug()) {
                    Logger.d("Plugin", "Plugin installPlugin start");
                }

                try {
                    File apkFile = new File(newPlugin.apkPath);
                    File dexFile = new File(newPlugin.dexPath);
                    File libFile = new File(newPlugin.libPath);
                    String sourceApkPath = newPlugin.apkPath + "/" + newPlugin.fileName();
                    if (!sourceApkPath.equals(dstPath)) {
                        if (Logger.debug()) {
                            Logger.d("Plugin", "Plugin sourceApkPath = " + dstPath);
                        }
                        if (apkFile.exists()) {
                            PluginUtil.deleteFile(apkFile);
                        }
                        apkFile.mkdirs();
                        apkFile = new File(dstPath);
                        File sourceApkFile = new File(sourceApkPath);
                        if (!sourceApkFile.exists()) {
                            sourceApkFile.createNewFile();
                        }
                        PluginUtil.copyFile(apkFile, sourceApkFile);
                    }
                    if (dexFile.exists()) {
                        PluginUtil.deleteFile(dexFile);
                    }
                    dexFile.mkdirs();
                    if (libFile.exists()) {
                        PluginUtil.deleteFile(libFile);
                    }
                    libFile.mkdirs();
                    PluginExtractor.extractPlugin(PluginManager.sContext, newPlugin.mApplicationInfo, dexFile, libFile);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw e;
                }
                PluginManager.sPluginMap.put(pluginPackageName, newPlugin);
                PluginManager.saveProxyPluginFace();
            }

            ProcessType processType = PluginUtil.getProcessType(PluginManager.sContext);
            Iterator<Map.Entry<String, Plugin>> it = PluginManager.sPluginMap.entrySet().iterator();
            boolean pluginChanged = false;
            while (it.hasNext()) {
                Map.Entry<String, Plugin> entry = it.next();
                if (entry == null) {
                    continue;
                }

                String pluginPackageName = entry.getKey();
                if (pluginPackageNameSet.contains(pluginPackageName)) {
                    continue;
                }

                Plugin plugin = entry.getValue();
                Plugin.PluginInfo pluginInfo = Plugin.mPluginInfoMap.get(plugin.packageName);
                if (pluginInfo != null && pluginInfo.processType == ProcessType.MAIN && processType == ProcessType.MAIN) {
                    if (Logger.debug()) {
                        Logger.d("Plugin", "uninstall plugin = " + pluginPackageName);
                    }

                    if (plugin != null) {
                        if (Logger.debug()) {
                            Logger.d("Plugin", "Plugin uninstallPlugin start");
                        }
                        File apkDir = new File(plugin.apkPath);
                        File dexDir = new File(plugin.dexPath);
                        File libDir = new File(plugin.libPath);
                        if (apkDir.exists()) {
                            PluginUtil.deleteFile(apkDir);
                        }

                        if (dexDir.exists()) {
                            PluginUtil.deleteFile(dexDir);
                        }

                        if (libDir.exists()) {
                            PluginUtil.deleteFile(libDir);
                        }

                        PluginManager.deletePluginFile(plugin.packageName);
                    }
                    Plugin.mPluginInfoMap.remove(pluginPackageName);
                    it.remove();
                    pluginChanged = true;
                    continue;
                }

                if (Logger.debug()) {
                    Logger.d("Plugin", "remove plugin = " + (((String) pluginPackageName)));
                }
                it.remove();
            }

            if (pluginChanged) {
                PluginManager.saveProxyPluginFace();
            }

            pluginManager.startInstalledPlugin();
        }
        PluginInstaller.notifyPluginInstallFinish();
    }

    public static boolean isCommonPluginLiteInstalled() {
        return PluginManager.getPlugin("com.bytedance.common.plugin.lite") != null;
    }

    private static void notifyPluginInstallFinish() throws Throwable {
        PluginInstaller.sPluginInstallFinishListenerInvoked = true;
        OnPluginInstallFinishListener onPluginInstallFinishListener = PluginInstaller.sOnPluginInstallFinishListener;
        if (onPluginInstallFinishListener != null) {
            onPluginInstallFinishListener.onPluginInstallFinished();
        }
    }

    public interface OnPluginInstallFinishListener {
        void onPluginInstallFinished() throws Throwable;
    }
}

